module ub (
    input logic clk,
    input logic rst_n,
    ub_rd_req_if.in u_ldma_rd_req_if,
    ub_rd_req_if.in u_aru_rd_req_if,
    aru_ub_dat_if.out u_aru_rd_dat_if,
    ldma_ub_dat_if.out u_ldma_rd_dat_if,
    aru_ub_wr_req_if.in u_aru_wr_req_if,
    gdma_ub_wr_req_if.in u_gdma_wr_req_if
);

    // Internal interface instances
    ub_rd_req_if u_arb_atomic_rd_req_if (
        .clk  (clk),
        .rst_n(rst_n)
    );

    gdma_ub_wr_req_if u_arb_normal_wr_req_if (
        .clk  (clk),
        .rst_n(rst_n)
    );

    gdma_ub_wr_req_if u_arb_atomic_wr_req_if (
        .clk  (clk),
        .rst_n(rst_n)
    );

    ub_rd_req_if u_gnt_rd_req0_if (
        .clk  (clk),
        .rst_n(rst_n)
    );

    ub_rd_req_if u_gnt_rd_req1_if (
        .clk  (clk),
        .rst_n(rst_n)
    );

    gdma_ub_wr_req_if u_gnt_wr_req_if (
        .clk  (clk),
        .rst_n(rst_n)
    );

    ldma_ub_dat_if u_aru_atomic_rd_dat_from_ram_if (
        .clk  (clk),
        .rst_n(rst_n)
    );

    ldma_ub_dat_if u_aru_atomic_rd_dat_to_alu_if (
        .clk  (clk),
        .rst_n(rst_n)
    );

    gdma_ub_wr_req_if u_aru_wr_req_to_fifo_if (
        .clk  (clk),
        .rst_n(rst_n)
    );

    gdma_ub_wr_req_if u_aru_wr_req_to_alu_if (
        .clk  (clk),
        .rst_n(rst_n)
    );

    gdma_ub_wr_req_if u_aru_wr_req_from_rdgen_to_wr_arbiter_if (
        .clk  (clk),
        .rst_n(rst_n)
    );

    gdma_ub_wr_req_if u_aru_wr_req_from_alu_to_wr_arbiter_if (
        .clk  (clk),
        .rst_n(rst_n)
    );

    // ========================================================================
    // Atomic Read Generator
    // ========================================================================
    ub_atomic_rdgen u_ub_atomic_rdgen (
        .clk                          (clk),
        .rst_n                        (rst_n),
        .u_aru_wr_req_in_if           (u_aru_wr_req_if),
        .u_aru_wr_req_to_fifo_if      (u_aru_wr_req_to_fifo_if),
        .u_aru_wr_req_to_wr_arbiter_if(u_aru_wr_req_from_rdgen_to_wr_arbiter_if),
        .u_ub_atomic_rd_req_if        (u_arb_atomic_rd_req_if)
    );

    // ========================================================================
    // Atomic FIFO - stores write requests while waiting for read data
    // ========================================================================
    logic            u_ub_wr_req_fifo_full;
    logic            u_ub_wr_req_fifo_empty;
    gdma_ub_wr_req_s aru_wr_req_from_fifo;
    logic            fifo_rd_en;

    // FIFO ready signal - backpressure when full
    assign u_aru_wr_req_to_fifo_if.rdy = ~u_ub_wr_req_fifo_full;

    // FIFO read enable: only when both RAM data and FIFO data will be consumed by ALU
    assign fifo_rd_en                  = u_aru_atomic_rd_dat_from_ram_if.vld && ~u_ub_wr_req_fifo_empty;

    common_fifo #(
        .DATA_WIDTH($bits(gdma_ub_wr_req_s)),
        .DEPTH     (8)
    ) u_ub_wr_req_fifo (
        .clk    (clk),
        .rst_n  (rst_n),
        .wr_en  (u_aru_wr_req_to_fifo_if.vld && ~u_ub_wr_req_fifo_full),
        .wr_data(u_aru_wr_req_to_fifo_if.pld),
        .rd_en  (fifo_rd_en),
        .rd_data(aru_wr_req_from_fifo),
        .full   (u_ub_wr_req_fifo_full),
        .empty  (u_ub_wr_req_fifo_empty)
    );

    // ========================================================================
    // Synchronize atomic read data and write request - simple one-cycle delay
    // ========================================================================
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            u_aru_atomic_rd_dat_to_alu_if.vld <= 1'b0;
            u_aru_wr_req_to_alu_if.vld        <= 1'b0;
            for (int i = 0; i < `N0; i++) begin
                for (int j = 0; j < `K0; j++) begin
                    u_aru_atomic_rd_dat_to_alu_if.dat[i][j] <= '0;
                end
            end
            u_aru_wr_req_to_alu_if.pld <= '0;
        end else begin
            // Simple pipeline: register both RAM data and FIFO data
            // Architecture guarantees both are valid when FIFO is read
            u_aru_atomic_rd_dat_to_alu_if.vld <= u_aru_atomic_rd_dat_from_ram_if.vld;
            u_aru_wr_req_to_alu_if.vld        <= u_aru_atomic_rd_dat_from_ram_if.vld;
            u_aru_atomic_rd_dat_to_alu_if.dat <= u_aru_atomic_rd_dat_from_ram_if.dat;
            u_aru_wr_req_to_alu_if.pld        <= aru_wr_req_from_fifo;
        end
    end

    // Assertion: verify architectural assumption that FIFO is never empty when RAM data is valid
    // synthesis translate_off
    always_ff @(posedge clk) begin
        if (rst_n && u_aru_atomic_rd_dat_from_ram_if.vld) begin
            assert (~u_ub_wr_req_fifo_empty)
            else $error("Atomic path violation: RAM data valid but FIFO empty!");
        end
    end
    // synthesis translate_on

    // ========================================================================
    // Read Arbiter - 3 inputs, 2 outputs
    // ========================================================================
    ub_rd_arbiter u_ub_rd_arbiter (
        .clk                   (clk),
        .rst_n                 (rst_n),
        .u_arb_normal_rd_req_if(u_aru_rd_req_if),
        .u_arb_atomic_rd_req_if(u_arb_atomic_rd_req_if),
        .u_ldma_rd_req_if      (u_ldma_rd_req_if),
        .u_gnt_rd_req0_if      (u_gnt_rd_req0_if),
        .u_gnt_rd_req1_if      (u_gnt_rd_req1_if)
    );

    // ========================================================================
    // Atomic ALU - performs add/mul operations (128B interface)
    // ========================================================================
    ub_atomic_alu u_ub_atomic_alu (
        .clk                          (clk),
        .rst_n                        (rst_n),
        .u_aru_atomic_rd_dat_if       (u_aru_atomic_rd_dat_to_alu_if),
        .u_aru_atomic_wr_req_if       (u_aru_wr_req_to_alu_if),
        .u_aru_wr_req_to_wr_arbiter_if(u_aru_wr_req_from_alu_to_wr_arbiter_if)
    );

    // ========================================================================
    // ARU normal/atomic write is already in ARU format (32B), direct pass-through
    // ========================================================================
    always_comb begin
        u_arb_normal_wr_req_if.vld = u_aru_wr_req_from_rdgen_to_wr_arbiter_if.vld;
        u_arb_normal_wr_req_if.pld = u_aru_wr_req_from_rdgen_to_wr_arbiter_if.pld;
    end
    assign u_aru_wr_req_from_rdgen_to_wr_arbiter_if.rdy = u_arb_normal_wr_req_if.rdy;  //反压机制

    always_comb begin
        u_arb_atomic_wr_req_if.vld = u_aru_wr_req_from_alu_to_wr_arbiter_if.vld;
        u_arb_atomic_wr_req_if.pld = u_aru_wr_req_from_alu_to_wr_arbiter_if.pld;
    end
    assign u_aru_wr_req_from_alu_to_wr_arbiter_if.rdy = u_arb_atomic_wr_req_if.rdy;  //反压机制

    // ========================================================================
    // Write Arbiter - 3 inputs, 1 output
    // ========================================================================
    ub_wr_arbiter u_ub_wr_arbiter (
        .clk                   (clk),
        .rst_n                 (rst_n),
        .u_arb_normal_wr_req_if(u_arb_normal_wr_req_if),
        .u_arb_atomic_wr_req_if(u_arb_atomic_wr_req_if),
        .u_gdma_wr_req_if      (u_gdma_wr_req_if),
        .u_gnt_wr_req_if       (u_gnt_wr_req_if)
    );

    // ========================================================================
    // UB RAM - 2 read ports, 1 write port
    // ========================================================================
    ub_ram u_ub_ram (
        .clk                   (clk),
        .rst_n                 (rst_n),
        .u_rd_req0_if          (u_gnt_rd_req0_if),
        .u_rd_req1_if          (u_gnt_rd_req1_if),
        .u_wr_req0_if          (u_gnt_wr_req_if),
        .u_aru_normal_rd_dat_if(u_aru_rd_dat_if),
        .u_aru_atomic_rd_dat_if(u_aru_atomic_rd_dat_from_ram_if),
        .u_ldma_rd_dat_if      (u_ldma_rd_dat_if)
    );

endmodule
